/**
 * moieo.net
 * @author Moieo
 */
package cn.moieo.carcontrol

import java.io.IOException
import java.net.ServerSocket
import java.net.Socket

/**
 * TCP 服务端实现[1,2](@ref)
 * @property port 监听端口，默认8888
 * @property onConnectionListener 连接状态回调接口
 */
class TCPServer(
    private val port: Int = 8888,
    private val onConnectionListener: OnConnectionListener? = null
) {
    // 服务端套接字（主Reactor）[1](@ref)
    private var serverSocket: ServerSocket? = null

    // 当前连接的客户端套接字（单连接限制实现）
    private var currentSocket: Socket? = null

    // 服务运行状态标志位（线程可见性保障）
    @Volatile
    private var isRunning = true

    // 初始化时启动服务线程（避免阻塞主线程）[1](@ref)
    init {
        Thread { startServer() }.start()
    }

    /**
     * 服务端主监听循环（使用sub Reactor模式）[1](@ref)
     * 1. 创建ServerSocket绑定端口
     * 2. 循环接受客户端连接
     * 3. 限制单连接并处理IO异常
     */
    private fun startServer() {
        try {
            serverSocket = ServerSocket(port)
            while (isRunning) {
                val socket = serverSocket!!.accept()

                // 单连接限制策略[2](@ref)
                if (currentSocket != null && !currentSocket!!.isClosed) {
                    socket.getOutputStream().write("Only one connection allowed\n".toByteArray())
                    socket.close()
                    continue
                }

                currentSocket = socket
                socket.inetAddress.hostAddress?.let {
                    onConnectionListener?.onConnectionStateChanged(ConnectionState.Connected(it))
                }
                // 为每个连接创建独立线程处理（可优化为线程池）[1](@ref)
                Thread { handleClient(socket) }.start()
            }
        } catch (e: IOException) {
            e.printStackTrace()
            onConnectionListener?.onConnectionStateChanged(ConnectionState.Error(e))
        }
    }

    /**
     * 客户端消息处理循环
     * @param socket 客户端套接字对象
     * 使用try-with-resources自动关闭流[1](@ref)
     */
    private fun handleClient(socket: Socket) {
        try {
            socket.getInputStream().use { input ->
                val buffer = ByteArray(1024)
                while (!socket.isClosed) {
                    val len = input.read(buffer)
                    if (len == -1) {
                        // 客户端主动断开连接
                        println("Client disconnected gracefully.")
                        break
                    }
                    val msg = String(buffer, 0, len)
                    println("Received: $msg")
                }
            }
        } catch (e: IOException) {
            // 捕获异常，可能是客户端意外断开
            println("Client disconnected unexpectedly: ${e.message}")
        } finally {
            // 确保在任何情况下都触发 onDisconnected
            onConnectionListener?.onConnectionStateChanged(ConnectionState.Disconnected)
            closeCurrentSocket()
        }
    }

    /**
     * 异步数据发送方法（线程安全）[1](@ref)
     * @param message 待发送字节数组
     * 使用独立线程避免阻塞主线程
     */
    fun send(message: ByteArray) {
        currentSocket?.let { socket ->
            if (!socket.isClosed) {
                Thread {
                    try {
                        val output = socket.getOutputStream()
                        output.write(message)
                        output.flush()
                    } catch (e: IOException) {
                        onConnectionListener?.onConnectionStateChanged(ConnectionState.Error(e))
                        closeCurrentSocket() // 如果发生异常，关闭连接
                    }
                }.start()
            }
        }
    }

    /**
     * 关闭当前连接（同步方法保障线程安全）[1](@ref)
     * 采用双检锁模式避免重复关闭
     */
    private fun closeCurrentSocket() {
        synchronized(this) {
            currentSocket?.also { socket ->
                try {
                    if (!socket.isClosed) socket.close()
                } catch (e: IOException) {
                    onConnectionListener?.onConnectionStateChanged(ConnectionState.Error(e))
                }
            }
        }
    }

    /**
     * 停止服务端运行[1](@ref)
     * 1. 设置运行标志位
     * 2. 关闭服务端套接字
     * 3. 清理现有连接
     */
    fun stop() {
        isRunning = false
        closeCurrentSocket()
        serverSocket?.let {
            try {
                it.close()
            } catch (e: IOException) {
                onConnectionListener?.onConnectionStateChanged(ConnectionState.Error(e))
            }
        }
    }

    /**
     * 连接状态回调接口[1](@ref)
     */
    interface OnConnectionListener {
        fun onConnectionStateChanged(state: ConnectionState)
    }

    /**
     * 内部状态类，用于封装连接状态信息
     */
    sealed class ConnectionState {
        data class Connected(val clientAddress: String) : ConnectionState()
        data object Disconnected : ConnectionState()
        data class Error(val exception: IOException) : ConnectionState()
    }
}